﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Markup;
using Red.Core;

namespace Red.Controls.Extensions
{
    /// <summary>
    ///     Markup extension for providing tooltip values from an external definition file
    /// </summary>
    public class TooltipExtension : MarkupExtension
    {
        #region Public Types

        public class TooltipInfo
        {
            public string Key { get; set; }
            public string Header { get; set; }
            public string Description { get; set; }
            public string Link { get; set; }
        }

        #endregion Public Types

        #region Data

        private static string _tootlipHelpUrl = "http://confluence:8090/display/CPT/Tooltips";

        private static Dictionary< string/*file*/, Dictionary< string/*key*/, TooltipInfo > > _tooltips = 
            new Dictionary< string, Dictionary< string, TooltipInfo > >();
        
        #endregion Data

        #region Properties

        /// <summary>
        ///     Definition file name (without extension, which is set to .tooltips). It should be placed in Data sub-directory
        /// </summary>
        public string File { get; set; }

        public string Extension { get; set; } = "tooltips";

        /// <summary>
        ///     Tooltip key within definition file
        /// </summary>
        public string Key { get; set; }
        public string Tag { get; set; } = "Tooltip";

        #endregion Properties

        #region MarkupExtension implementation
        
        public override object ProvideValue( IServiceProvider serviceProvider )
        {
            return ProvideTooltip();
        }

        #endregion MarkupExtension implementation

        #region Public Methods
        
        /// <summary>
        /// A method for using our fancy tooltips from code behind
        /// </summary>
        /// <param name="file">The file in which the tooltip is defined</param>
        /// <param name="key">The id of the tooltip</param>
        /// <param name="suppressErrors">If false, any error that occurs retrieving the tooltip will be displayed on the tooltip. If True, no tooltip will be displayed in the event of an error</param>
        /// <returns>Tooltip string, or null if suppressed</returns>
        public static string GetTooltip( string file, string key, bool suppressErrors = false )
        {
            var ext = new TooltipExtension() { File = file, Key = key };
            return ext.ProvideTooltip( suppressErrors );
        }
        public static string GetTooltip( string file, string key, string extension, string tag, bool suppressErrors = false )
        {
            var ext = new TooltipExtension() { File = file, Key = key, Extension = extension, Tag = tag };
            return ext.ProvideTooltip( suppressErrors );
        }

        public static TooltipInfo GetTooltipElements( string file, string key, bool suppressErrors = false )
        {
            var ext = new TooltipExtension() { File = file, Key = key };
            return ext.GetTooltipElements( suppressErrors );
        }

        public TooltipInfo GetTooltipElements( bool suppressErrors = false )
        {
            Dictionary<string, TooltipInfo> tooltipsByKey;

            if ( !_tooltips.TryGetValue( File, out tooltipsByKey ) )
            {
                tooltipsByKey = PreCache( File, Extension, Tag );

                if ( tooltipsByKey != null )
                {
                    _tooltips.Add( File, tooltipsByKey );
                }
                else
                {
                    if( suppressErrors )
                    {
                        return null;
                    }
                    else
                    {
                        return new TooltipInfo()
                        {
                            Key = Key,
                            Header = @"<< Error >>",
                            Description = $"Could not read tooltip definition file '{File}'",
                            Link = _tootlipHelpUrl
                        };
                    }
                }
            }

            TooltipInfo tooltip;

            if ( !tooltipsByKey.TryGetValue( Key, out tooltip ) )
            {
                if( suppressErrors )
                {
                    return null;
                }
                else
                {
                    return new TooltipInfo()
                    {
                        Key = Key,
                        Header = @"<< Error >>",
                        Description = $"Tooltip '{Key}' not found in file '{File}'",
                        Link = _tootlipHelpUrl
                    };
                }
            }

            return tooltip;

        }

        #endregion Public Methods

        #region Private methods

        private static Dictionary<string, TooltipInfo> PreCache( string fileName, string extension, string tag )
        {
            IEnumerable< TooltipInfo> tooltips = StringProvider.Read<TooltipInfo>( $"{fileName}.{extension}", tag );
            if ( tooltips == null ) return null;

            return tooltips.ToDictionary( info => info.Key );
        }

        private string ProvideTooltip( bool suppressErrors = false )
        {
            TooltipInfo tooltip = GetTooltipElements( suppressErrors );

            if( tooltip == null )
            {
                return null;
            }

            return tooltip.Header + "|" + tooltip.Description + "|" + tooltip.Link;
        }

        #endregion Private methods
    }
}
